=begin pod :kind("Type") :subkind("class") :category("basic")

=TITLE class Telemetry

=SUBTITLE Collect performance state for analysis

    class Telemetry { }

B<Note: > This class is a Rakudo-specific feature and not standard Raku.

On creation, a C<Telemetry> object contains a snapshot of various aspects of
the current state of the virtual machine.  This is in itself useful, but
generally one needs two snapshots for the difference (which is a
L<Telemetry::Period|/type/Telemetry::Period> object).

The Telemetry object is really a collection of snapshots taken by different
"instruments".  By default, the
L<Telemetry::Instrument::Usage|/type/Telemetry::Instrument::Usage>
and L<Telemetry::Instrument::ThreadPool|/type/ThreadPoolScheduler>
instruments are activated.

The Telemetry (and Telemetry::Period) object also C<Associative>.  This means
that you can treat a Telemetry object as a read-only C<Hash>, with all of the
data values of the instruments as keys.

You can determine which instruments C<Telemetry> should use by setting the
C<$*SAMPLER> dynamic variable, which is a
L<Telemetry::Sampler|/type/Telemetry::Sampler> object.

Currently, the following instruments are supported by the Rakudo core:

=item Telemetry::Instrument::Usage

Provides (in alphabetical order): C<cpu>, C<cpu-sys>, C<cpu-user>, C<cpus>,
C<id-rss>, C<inb>, C<invcsw>, C<is-rss>, C<ix-rss>, C<majf>, C<max-rss>,
C<minf>, C<mrcv>, C<msnd>, C<nsig>, C<nswp>, C<volcsw>, C<outb>, C<util%>
and C<wallclock>.  For complete documentation of the meaning of these data
values, see L<Telemetry::Instrument::Usage|/type/Telemetry::Instrument::Usage>.

=item Telemetry::Instrument::Thread

Provides (in alphabetical order): C<tad>, C<tcd>, C<thid>, C<tjd>, C<tsd> and
C<tys>.  For complete documentation of the meaning of these data values, see
L<Telemetry::Instrument::Thread|/type/Telemetry::Instrument::Thread>.

=item Telemetry::Instrument::ThreadPool

Provides (in alphabetical order): C<atc>, C<atq>, C<aw>, C<gtc>, C<gtq>, C<gw>,
C<s>, C<ttc>, C<ttq> and C<tw>.  For complete documentation of the meaning of
these data values, see
L<Telemetry::Instrument::ThreadPool|/type/ThreadPoolScheduler>.

=item Telemetry::Instrument::AdHoc

Does not provide any data by itself: one must indicate which variables are
to be monitored, which will then become available as methods with the same name
on the instrument.  For complete documentation, see
L<Telemetry::Instrument::AdHoc|/type/Telemetry::Instrument::AdHoc>.

=head2 routine T

    sub T()

Shortcut for C<Telemetry.new>.  It is exported by default.  Since the
C<Telemetry> class also provides an C<Associative> interface, one can easily
interpolate multiple values in a single statement:

=begin code
use Telemetry;
say "Used {T<max-rss cpu>} (KiB CPU) so far";
=end code

=head2 routine snap

    multi sub snap(--> Nil)
    multi sub snap(Str:D $message --> Nil)
    multi sub snap(Str $message = "taking heap snapshot...", :$heap!)
    multi sub snap(@s --> Nil)

The C<snap> subroutine is shorthand for creating a new C<Telemetry> object and
pushing it to an array for later processing.  It is exported by default. From
release 2021.12, it returns the filename it's storing the snapshots in the
case it's provided with a C<:$heap> associative parameter.

=begin code
use Telemetry;
my @t;
for ^5 {
    snap(@t);
    # do some stuff
    LAST snap(@t);
}
=end code

If no array is specified, it will use an internal array for convenience.

=head2 routine snapper

    sub snapper($sleep = 0.1, :$stop, :$reset --> Nil)

The C<snapper> routine starts a separate thread that will call C<snap>
repeatedly until the end of program.  It is exported by default.

By default, it will call C<snap> every B<0.1> second.  The only positional
parameter is taken to be the delay between C<snap>s.

Please see the L<snapper module|#module_snapper> for externally starting a snapper without
having to change the code.  Simply adding C<-Msnapper> as a command line
parameter, will then start a snapper for you.

=head2 routine periods

    multi sub periods( --> Seq)
    multi sub periods(@s --> Seq)

The C<periods> subroutine processes an array of C<Telemetry> objects and
generates a L<Seq|/type/Seq> of C<Telemetry::Period> objects out of that.  It is exported
by default.

=begin code :preamble<my @t;use Telemetry;>
.<cpu wallclock>.say for periods(@t);

# OUTPUT:
# ====================
# (164 / 160)
# (23 / 21)
# (17 / 17)
# (15 / 16)
# (29 / 28)
=end code

If no array is specified, it will use the internal array of C<snap> without
parameters B<and> will reset that array upon completion (so that new C<snap>s
can be added again).

=begin code
use Telemetry;
for ^5 {
    snap;
    LAST snap;
}
say .<cpu wallclock>.join(" / ") for periods;

# OUTPUT:
# ====================
# 172 / 168
# 24 / 21
# 17 / 18
# 17 / 16
# 27 / 27
=end code

If only one C<snap> was done, another C<snap> will be done to create at least
one C<Telemetry::Period> object.

=head2 routine report

    multi sub report(:@columns, :$legend, :$header-repeat, :$csv, :@format)

The C<report> subroutine generates a report about an array of C<Telemetry>
objects.  It is exported by default.  These can have been created by regularly
calling C<snap>, or by having a L<snapper|/routine/snapper> running.  If no positional parameter
is used, it will assume the internal array to which the parameterless C<snap>
pushes.

Below are the additional named parameters of C<report>.

=item C<:columns>

Specify the names of the columns to be included in the report.  Names can
be specified with the column name (e.g. C<gw>).  If not specified, defaults to
what is specified in the C<RAKUDO_REPORT_COLUMNS> environment variable.
If that is not set either, defaults to:

    =begin code :lang<text>
    wallclock util% max-rss gw gtc tw ttc aw atc
    =end code

=item C<:header-repeat>

Specifies after how many lines the header should be repeated in the report.
If not specified, defaults to what is specified in the
C<RAKUDO_REPORT_HEADER_REPEAT> environment variable.  If that is not set either,
defaults to 32.

=item C<:legend>

Specifies whether a legend should be added to the report.  If not specified,
defaults to what is specified in the C<RAKUDO_REPORT_LEGEND> environment variable.
If that is not set either, defaults to True.

If there are C<snap>s available in the internal array at the end of the
program, then C<report> will be automatically generated and printed on C<STDERR>.

=head2 module snapper

Start a thread taking repeated system state snapshots.

This module contains no subroutines or methods or anything.  It is intended
as a shortcut for starting the L<snapper|/routine/snapper> subroutine of the C<Telemetry> module,
allowing taking snapshots of the execution of a program without needing to change
the program.  Simple loading the module with C<-Msnapper> will do all that is
needed to start the snapper, and have a report printed on STDERR upon completion
of the program.

The C<RAKUDO_SNAPPER> environment variable can be set to indicate the time
between snapshots.  If not specified, it will default to B<0.1> seconds.

=end pod

# vim: expandtab softtabstop=4 shiftwidth=4 ft=perl6
